﻿using Newtonsoft.Json;
using System.Drawing;
using System.Windows;
using VisionDesigner;
using VisionDesigner.BeadGuide;
using VM.Common.Helper;
using VM.Start.Common.Hik;
using VM.Start.Controls;

namespace Plugin.BeadGuide
{

    #region enum
    public enum eSelectImageCommand
    {
        LocalImage,
        OtherImage
    }

    #endregion

    [JsonObject(MemberSerialization.OptOut)]
    public class BeadGuideEditViewModel : NotifyPropertyBase
    {
        #region  属性

        [Newtonsoft.Json.JsonIgnore]
        public BeadGuideViewModel beadGuideViewModel;
        [Newtonsoft.Json.JsonIgnore]
        public BeadGuideEditView view;
        [Newtonsoft.Json.JsonIgnore]
        public CMvdImage LocalImage;

        // 路径提取工具
        [Newtonsoft.Json.JsonIgnore]
        public CBeadGuideTool _BeadGuideTool = new CBeadGuideTool();
        //轨迹
        public List<CMvdShape> _TrajList = new List<CMvdShape>();
        // 绘制轮廓
        public List<CMvdPointSetF> _DrawOutlineList = new List<CMvdPointSetF>();
        // 绘制卡尺框
        public List<CMvdRectangleF> _DrawCaliperBoxList = new List<CMvdRectangleF>();
        // 模板点
        public CMvdPointSetF edgePoint = new CMvdPointSetF();

        [Newtonsoft.Json.JsonIgnore]
        public TemplateModel m_TemplateModel;

        #region 训练图像
        public uint Width;
        public uint Height;
        public MVD_PIXEL_FORMAT PIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
        public MVD_IMAGE_DATA_INFO ImageData = null;
        [Newtonsoft.Json.JsonIgnore]
        private CMvdImage _TrainImage;
        [Newtonsoft.Json.JsonIgnore]
        public CMvdImage TrainImage
        {
            get
            {
                if ((_TrainImage == null || _TrainImage.IsEmpty) &&
                    ImageData != null && ImageData.stDataChannel[0].arrDataBytes != null &&
                    Width != 0 && Height != 0 && PIXEL_FORMAT != MVD_PIXEL_FORMAT.MVD_PIXEL_NULL)
                {
                    _TrainImage = new CMvdImage();
                    _TrainImage.InitImage(Width, Height, PIXEL_FORMAT, ImageData);
                }
                return _TrainImage;
            }
            set
            {
                _TrainImage = value;
                if (_TrainImage != null && !_TrainImage.IsEmpty)
                {
                    Width = _TrainImage.Width;
                    Height = _TrainImage.Height;
                    PIXEL_FORMAT = _TrainImage.PixelFormat;
                    ImageData = _TrainImage.GetImageData();
                }
                else
                {
                    Width = 0;
                    Height = 0;
                    PIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
                    ImageData = null;
                }
                LearnMatch.Image = value;
            }
        }
        #endregion
        #region 训练结果图像
        public uint rWidth;
        public uint rHeight;
        public MVD_PIXEL_FORMAT rPIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
        public MVD_IMAGE_DATA_INFO rImageData = null;
        [Newtonsoft.Json.JsonIgnore]
        private CMvdImage _rTrainImage;
        [Newtonsoft.Json.JsonIgnore]
        private CMvdImage rTrainImage
        {
            get
            {
                if ((_rTrainImage == null || _rTrainImage.IsEmpty) &&
                    rImageData != null && rImageData.stDataChannel[0].arrDataBytes != null &&
                    rWidth != 0 && rHeight != 0 && rPIXEL_FORMAT != MVD_PIXEL_FORMAT.MVD_PIXEL_NULL)
                {
                    _rTrainImage = new CMvdImage();
                    _rTrainImage.InitImage(rWidth, rHeight, rPIXEL_FORMAT, rImageData);
                }
                return _rTrainImage;
            }
            set
            {
                _rTrainImage = value;
                if (_rTrainImage != null && !_rTrainImage.IsEmpty)
                {
                    rWidth = _rTrainImage.Width;
                    rHeight = _rTrainImage.Height;
                    rPIXEL_FORMAT = _rTrainImage.PixelFormat;
                    rImageData = _rTrainImage.GetImageData();
                }
                else
                {
                    rWidth = 0;
                    rHeight = 0;
                    rPIXEL_FORMAT = MVD_PIXEL_FORMAT.MVD_PIXEL_NULL;
                    rImageData = null;
                }
                TemplateWindow.Image = value;
            }
        }
        #endregion
        #endregion
        #region  数据接口

        [Newtonsoft.Json.JsonIgnore]
        public VMDisplayControl _LearnMatch;
        [Newtonsoft.Json.JsonIgnore]
        public VMDisplayControl LearnMatch
        {
            get
            {
                if (_LearnMatch == null)
                {
                    _LearnMatch = new VMDisplayControl();
                    _LearnMatch.MVDRender.MVDShapeChangedEvent += MVDRender_MVDShapeChangedEvent;
                }
                return _LearnMatch;
            }
        }

        [Newtonsoft.Json.JsonIgnore]
        private VMDisplayControl _TemplateWindow;
        [Newtonsoft.Json.JsonIgnore]
        public VMDisplayControl TemplateWindow
        {
            get
            {
                if (_TemplateWindow == null)
                {
                    _TemplateWindow = new VMDisplayControl();
                }
                return _TemplateWindow;
            }
        }

        /// <summary>
        /// 参数
        /// </summary>
        public BeadGuideEditModel _Param;
        public BeadGuideEditModel Param
        {
            get
            {
                if (_Param == null)
                {
                    _Param = new BeadGuideEditModel();
                }
                return _Param;
            }
            set
            {
                Set(ref _Param, value);
            }
        }

        /// <summary>
        /// 运行模式枚举值
        /// </summary>
        private Array _RunningModeArray = Enum.GetValues(typeof(RunModeEnum));
        public Array RunningModeArray
        {
            get => _RunningModeArray;
            set => Set(ref _RunningModeArray, value);
        }

        /// <summary>
        /// 运行模式
        /// </summary>
        private RunModeEnum _RunningMode = RunModeEnum.寻找边缘;
        public RunModeEnum RunningMode
        {
            get
            {
                if (_BeadGuideTool.BasicParam.RunningMode == MVD_BEAD_GUIDE_RUNNING_MODE.MVD_BEAD_GUIDE_FIX_POINT)
                {
                    _RunningMode = RunModeEnum.拟合点;
                }
                else if (_BeadGuideTool.BasicParam.RunningMode == MVD_BEAD_GUIDE_RUNNING_MODE.MVD_BEAD_GUIDE_FIND_EDGE)
                {
                    _RunningMode = RunModeEnum.寻找边缘;
                }
                return _RunningMode;
            }
            set
            {
                Set(ref _RunningMode, value);
                if (_RunningMode == RunModeEnum.拟合点)
                {
                    _BeadGuideTool.BasicParam.RunningMode = MVD_BEAD_GUIDE_RUNNING_MODE.MVD_BEAD_GUIDE_FIX_POINT;
                }
                else if (_RunningMode == RunModeEnum.寻找边缘)
                {
                    _BeadGuideTool.BasicParam.RunningMode = MVD_BEAD_GUIDE_RUNNING_MODE.MVD_BEAD_GUIDE_FIND_EDGE;
                }
            }
        }

        private int _SamplingPtNum = 10;
        public int SamplingPtNum
        {
            get
            {
                if (_BeadGuideTool.BasicParam.SamplingPointNum != _SamplingPtNum)
                {
                    _BeadGuideTool.BasicParam.SamplingPointNum = _SamplingPtNum;
                }
                return _SamplingPtNum;
            }
            set
            {
                Set(ref _SamplingPtNum, value);
                _BeadGuideTool.BasicParam.SamplingPointNum = _SamplingPtNum;
            }
        }

        private float _ExpectOffsetDistance;
        public float ExpectOffsetDistance
        {
            get
            {
                _ExpectOffsetDistance = _BeadGuideTool.BasicParam.ExpectOffsetDistance;
                return _ExpectOffsetDistance;
            }
            set
            {
                Set(ref _ExpectOffsetDistance, value);
                _BeadGuideTool.BasicParam.ExpectOffsetDistance = _ExpectOffsetDistance;
            }
        }


        #endregion
        #region 指令
        [Newtonsoft.Json.JsonIgnore]
        private CommandBase _SelectImageCommand;
        [Newtonsoft.Json.JsonIgnore]
        public CommandBase SelectImageCommand
        {
            get
            {
                if (_SelectImageCommand == null)
                {
                    _SelectImageCommand = new CommandBase(
                        (obj) =>
                        {
                            try
                            {
                                eSelectImageCommand par = (eSelectImageCommand)obj;
                                switch (par)
                                {
                                    case eSelectImageCommand.LocalImage:
                                        TrainImage = LocalImage;
                                        break;
                                    case eSelectImageCommand.OtherImage:
                                        Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
                                        dlg.Filter = "所有图像文件 | *.bmp; *.pcx; *.png; *.jpg; *.gif;*.tif; *.ico; *.dxf; *.cgm; *.cdr; *.wmf; *.eps; *.emf";
                                        if (dlg.ShowDialog() == true)
                                        {
                                            RImage rImage = new RImage();
                                            rImage.InitImage(dlg.FileName, VisionDesigner.MVD_PIXEL_FORMAT.MVD_PIXEL_MONO_08);
                                            TrainImage = rImage;
                                        }
                                        break;
                                    default:
                                        throw new ArgumentOutOfRangeException();
                                }
                            }
                            catch (Exception ex)
                            {

                            }
                        }
                    );
                }
                return _SelectImageCommand;
            }
        }

        [Newtonsoft.Json.JsonIgnore]
        private CommandBase _learnCommand;
        [Newtonsoft.Json.JsonIgnore]
        public CommandBase LearnCommand
        {
            get
            {
                if (_learnCommand == null)
                {
                    _learnCommand = new CommandBase((obj) =>
                    {
                        RunTool();
                    });
                }
                return _learnCommand;
            }
        }

        [Newtonsoft.Json.JsonIgnore]
        private CommandBase _ConfirmCommand;
        [Newtonsoft.Json.JsonIgnore]
        public CommandBase ConfirmCommand
        {
            get
            {
                if (_ConfirmCommand == null)
                {
                    _ConfirmCommand = new CommandBase((obj) =>
                    {
                        if (view != null)
                        {
                            RunTool();
                            if (m_TemplateModel == null)
                            {
                                m_TemplateModel = new TemplateModel();

                                // 确保新模板的名称唯一
                                string baseName = "新建模板";
                                int index = 1;
                                string newName;

                                // 循环检查名称是否已存在
                                do
                                {
                                    newName = $"{baseName}{index}";
                                    index++;
                                } while (beadGuideViewModel.TemplateList.Any(template => template.Name == newName));

                                m_TemplateModel.Name = newName;
                                m_TemplateModel.Index = beadGuideViewModel.TemplateList.Count;
                                beadGuideViewModel.TemplateList.Add(m_TemplateModel);
                            }
                            m_TemplateModel.Data = this;
                            beadGuideViewModel.SelectedTemplate = m_TemplateModel;
                            view.Close();
                        }
                    });
                }
                return _ConfirmCommand;
            }
        }

        #endregion
        #region 方法
        /// <summary>
        /// 初始化加载
        /// </summary>
        public void Loaded()
        {
            if (TrainImage != null && !TrainImage.IsEmpty)
            {
                LearnMatch.Image = TrainImage;
                foreach (var item in _TrajList)
                {
                    LearnMatch.AddShape(item);
                }
            }
            if (rTrainImage != null && !rTrainImage.IsEmpty)
            {
                TemplateWindow.Image = rTrainImage;
                TemplateWindow.MVDRender.Display(MVDRenderActivex.MVD_REFRESH_MODE.Sync);
                TemplateWindow.AddShape(edgePoint);
                TemplateWindow.MVDRender.Display();
            }
        }

        /// <summary>
        /// 清理卡尺
        /// </summary>
        /// <param name="caliperBoxList"></param>
        private void ClearCaliperBoxList(List<CMvdRectangleF> caliperBoxList)
        {
            foreach (var item in caliperBoxList)
            {
                LearnMatch.RemoveShape(item);
            }
            caliperBoxList.Clear();
        }

        /// <summary>
        /// 清理轮廓
        /// </summary>
        /// <param name="drawEdgePointList"></param>
        private void ClearOutline(List<CMvdPointSetF> drawEdgePointList)
        {
            foreach (var item in drawEdgePointList)
            {
                LearnMatch.RemoveShape(item);
            }
            drawEdgePointList.Clear();
        }

        /// <summary>
        /// 点是否在图像外
        /// </summary>
        /// <param name="point"></param>
        /// <param name="imageWidth"></param>
        /// <param name="imageHeight"></param>
        /// <returns></returns>
        private bool IsPointOutOfImage(MVD_POINT_F point, float imageWidth, float imageHeight)
        {
            if ((point.fX - 0 < Single.Epsilon)
            || (point.fY - 0 < Single.Epsilon)
            || (imageWidth - point.fX < Single.Epsilon)
            || (imageHeight - point.fY < Single.Epsilon))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 绘制轮廓
        /// </summary>
        /// <param name="drawEdgePointList"></param>
        private void DrawOutline(List<CBeadGuideEdgePointInfo> drawEdgePointList, UInt32 imageWidth, UInt32 imageHeight)
        {
            foreach (var item in drawEdgePointList)
            {
                if (IsPointOutOfImage(item.EdgePoint, imageWidth, imageHeight))
                {
                    continue;
                }

                CMvdPointSetF EdgePoint = new CMvdPointSetF();

                switch (item.Status)
                {
                    case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_USED:
                        {
                            EdgePoint.BorderColor = new MVD_COLOR(0, 255, 0, 255);
                            EdgePoint.PointsList.Add(item.EdgePoint);

                        }
                        break;
                    case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_NO_USED:
                        {
                            EdgePoint.BorderColor = new MVD_COLOR(255, 255, 0, 255);
                            EdgePoint.PointsList.Add(item.EdgePoint);

                        }
                        break;
                    case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_NO_FIND:
                        {
                            EdgePoint.BorderColor = new MVD_COLOR(255, 0, 0, 255);
                            EdgePoint.PointsList.Add(item.EdgePoint);
                        }
                        break;
                    default:
                        break;
                }
                LearnMatch.AddShape(EdgePoint);
                _DrawOutlineList.Add(EdgePoint);
            }
            LearnMatch.MVDRender.Display();
        }

        /// <summary>
        /// 绘制卡尺
        /// </summary>
        /// <param name="caliperBoxList"></param>
        private void DrawCaliperBoxList(List<CMvdRectangleF> caliperBoxList, float imageWidth, float imageHeight)
        {
            foreach (var item in caliperBoxList)
            {
                if (IsPointOutOfImage(new MVD_POINT_F(item.CenterX, item.CenterY), imageWidth, imageHeight))
                {
                    continue;
                }

                CMvdRectangleF drawCaliperBox = new CMvdRectangleF(item);
                drawCaliperBox.BorderColor = new MVD_COLOR(0, 0, 255, 255);
                LearnMatch.AddShape(drawCaliperBox);
                _DrawCaliperBoxList.Add(drawCaliperBox);
            }
            LearnMatch.MVDRender.Display();
        }

        /// <summary>
        /// 计算轮廓点的最小包围框
        /// </summary>
        private System.Windows.Rect CalculateBoundingBox(List<CBeadGuideEdgePointInfo> edgePoints, uint imageWidth, uint imageHeight)
        {
            double minX = imageWidth, minY = imageHeight, maxX = 0, maxY = 0;

            foreach (var pointInfo in edgePoints)
            {
                var point = pointInfo.EdgePoint;
                if (IsPointOutOfImage(point, imageWidth, imageHeight)) continue;

                if (point.fX < minX) minX = point.fX;
                if (point.fY < minY) minY = point.fY;
                if (point.fX > maxX) maxX = point.fX;
                if (point.fY > maxY) maxY = point.fY;
            }
            minX = Math.Max(0, minX - 10 - Param.ParamInt["CaliperHeight"]);
            minY = Math.Max(0, minY - 10 - Param.ParamInt["CaliperHeight"]);
            maxX = Math.Min(imageWidth - 1, maxX + 10 + Param.ParamInt["CaliperHeight"]);
            maxY = Math.Min(imageHeight - 1, maxY + 10 + Param.ParamInt["CaliperHeight"]);

            return new System.Windows.Rect((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
        }

        /// <summary>
        /// 裁剪图像
        /// </summary>
        private Bitmap CropImage(Bitmap sourceImage, System.Windows.Rect croppingRegion)
        {
            return sourceImage.Clone(new System.Drawing.Rectangle((int)croppingRegion.X, (int)croppingRegion.Y, (int)croppingRegion.Width, (int)croppingRegion.Height), sourceImage.PixelFormat);
        }

        /// <summary>
        /// 在裁剪后的图像中绘制轮廓
        /// </summary>
        private void DrawOutlineInCroppedImage(List<CBeadGuideEdgePointInfo> edgePoints, Rect croppingRegion)
        {
            foreach (var item in edgePoints)
            {
                var point = item.EdgePoint;
                if (point.fX < croppingRegion.X || point.fX > croppingRegion.X + croppingRegion.Width ||
                    point.fY < croppingRegion.Y || point.fY > croppingRegion.Y + croppingRegion.Height)
                {
                    continue; // 忽略裁剪框外的点
                }

                var relativePoint = new MVD_POINT_F(point.fX - (float)croppingRegion.X, point.fY - (float)croppingRegion.Y);

                switch (item.Status)
                {
                    case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_USED:
                        edgePoint.BorderColor = new MVD_COLOR(0, 255, 0, 255);
                        break;
                    case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_NO_USED:
                        edgePoint.BorderColor = new MVD_COLOR(255, 255, 0, 255);
                        break;
                    case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_NO_FIND:
                        edgePoint.BorderColor = new MVD_COLOR(255, 0, 0, 255);
                        break;
                }
                edgePoint.PointsList.Add(relativePoint);
                TemplateWindow.AddShape(edgePoint);
            }

            TemplateWindow.MVDRender.Display();
        }

        /// <summary>
        /// 绘制裁剪后的卡尺框
        /// </summary>
        private void DrawCaliperBoxList(List<CMvdRectangleF> caliperBoxList, float croppedWidth, float croppedHeight, Rect croppingRegion)
        {
            foreach (var item in caliperBoxList)
            {
                var centerX = item.CenterX;
                var centerY = item.CenterY;

                if (centerX < croppingRegion.X || centerX > croppingRegion.X + croppingRegion.Width ||
                    centerY < croppingRegion.Y || centerY > croppingRegion.Y + croppingRegion.Height)
                {
                    continue; // 忽略裁剪框外的点
                }

                var relativeRect = new CMvdRectangleF(item);
                relativeRect.CenterX -= (float)croppingRegion.X;
                relativeRect.CenterY -= (float)croppingRegion.Y;

                relativeRect.BorderColor = new MVD_COLOR(0, 0, 255, 255);
                TemplateWindow.AddShape(relativeRect);
            }

            TemplateWindow.MVDRender.Display();
        }

        public bool RunTool()
        {
            try
            {
                if ((null == _BeadGuideTool) || (null == TrainImage))
                {
                    throw new MvdException(MVD_MODULE_TYPE.MVD_MODUL_APP, MVD_ERROR_CODE.MVD_E_CALLORDER);
                }

                // 清理绘制结果
                //ClearArc(ref _DrawArc);
                ClearCaliperBoxList(_DrawCaliperBoxList);
                ClearOutline(_DrawOutlineList);

                // 算法处理
                _BeadGuideTool.InputImage = TrainImage;

                _BeadGuideTool.BasicParam.TrajList.Clear();
                foreach (var item in _TrajList)
                {
                    _BeadGuideTool.BasicParam.TrajList.Add(item);
                }
                Param.UpdateParam(_BeadGuideTool);
                _BeadGuideTool.Run();
                CBeadGuideResult BeadGuideResult = _BeadGuideTool.Result;
                // 绘制轮廓点
                List<CBeadGuideEdgePointInfo> BeadGuideEdgePointList = BeadGuideResult.EdgePointInfo;
                DrawOutline(BeadGuideEdgePointList, TrainImage.Width, TrainImage.Height);
                DrawCaliperBoxList(BeadGuideResult.CaliperBoxList, TrainImage.Width, TrainImage.Height);

                // 计算轮廓的裁剪范围
                var croppingRegion = CalculateBoundingBox(BeadGuideEdgePointList, TrainImage.Width, TrainImage.Height);
                // 裁剪图像
                Bitmap sourceImage = null;
                CMvdImage cMvdImage = new CMvdImage();
                ImageTool.ConvertMVDImage2Bitmap(TrainImage, ref sourceImage);
                ImageTool.ConvertBitmap2MVDImage(CropImage(sourceImage, croppingRegion), cMvdImage);
                TemplateWindow.Image = rTrainImage = cMvdImage;
                // 在裁剪后的图像中绘制轮廓点
                DrawOutlineInCroppedImage(BeadGuideEdgePointList, croppingRegion);
                // 绘制裁剪后的卡尺
                DrawCaliperBoxList(BeadGuideResult.CaliperBoxList, (float)croppingRegion.Width, (float)croppingRegion.Height, croppingRegion);
            }
            catch (MvdException ex)
            {
                string MsgError = String.Format("Fail to running the tool, Module : {0}, ErrorCode : 0x{1}, Message : {2}.\r\n", ex.ModuleType.ToString(), ex.ErrorCode.ToString("X"), ex.Message);
            }
            catch (System.Exception ex)
            {
                string MsgError = String.Format("Fail to running the tool, Message : {0}, StackTrace : {1}.\r\n", ex.Message, ex.StackTrace);
            }
            return true;
        }

        #endregion
        #region 事件
        public void MVDRender_MVDShapeChangedEvent
        (
        MVDRenderActivex.MVD_SHAPE_EVENT_TYPE enEventType,
        MVD_SHAPE_TYPE enShapeType,
        CMvdShape cShapeObj
        )
        {
            if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_SELECTED == enEventType)
            {
                return;
            }
            if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_EDITED == enEventType)
            {
                return;
            }

            if (MVD_SHAPE_TYPE.MvdShapeAnnularSector == enShapeType || MVD_SHAPE_TYPE.MvdShapePolylineSegment == enShapeType)
            {
                if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_ADDED == enEventType)
                {
                    if (_TrajList.Count > 0)
                    {

                        foreach (var item in _TrajList)
                        {
                            LearnMatch.RemoveShape(item);
                        }
                        _TrajList.Clear();
                    }
                    _TrajList.Add(cShapeObj);
                }
                else if (MVDRenderActivex.MVD_SHAPE_EVENT_TYPE.MVD_SHAPE_DELETED == enEventType)
                {
                    foreach (var item in _DrawOutlineList)
                    {
                        if (item == cShapeObj)
                        {
                            _DrawOutlineList.Remove(item);
                            LearnMatch.RemoveShape(item);
                            break;
                        }
                    }

                    foreach (var item in _DrawCaliperBoxList)
                    {
                        if (item == cShapeObj)
                        {
                            _DrawCaliperBoxList.Remove(item);
                            LearnMatch.RemoveShape(item);
                            break;
                        }
                    }
                    _TrajList.Remove(cShapeObj);
                    _TrajList.Add(cShapeObj);
                }
                return;
            }
        }
    }
    #endregion

}
